;/*
;nasm boot.asm -o boot.com
;*/
;%define	_BOOT_DEBUG_	; 做 Boot Sector 时一定将此行注释掉!将此行打开后用 nasm Boot.asm -o Boot.com 做成一个.COM文件易于调试

%ifdef	_BOOT_DEBUG_
	org  0100h			; 调试状态, 做成 .COM 文件, 可调试
%else
	org  07c00h			; Boot 状态, Bios 将把 Boot Sector 加载到 0:7C00 处并开始执行
%endif
;================================================================================================
%ifdef	_BOOT_DEBUG_
BaseOfStack		equ	0100h	; 调试状态下堆栈基地址(栈底, 从这个位置向低地址生长)
%else
BaseOfStack		equ	07c00h	; 堆栈基地址(栈底, 从这个位置向低地址生长)
%endif

SectorsOfMBR		equ 63		;MBR 大小
BaseOfLoader		equ	09000h	; LOADER.BIN 被加载到的位置 ----  段地址
OffsetOfLoader		equ	0100h	; LOADER.BIN 被加载到的位置 ----  偏移地址
;;========================================================
		jmp short LABEL_START		; Start to boot.
		nop				; 这个 nop 不可少

		; 下面是 FAT32 磁盘的头
		BS_OEMName				DB 'OSMinix.'	; OEM String, 必须 8 个字节
		BPB_BytsPerSec			DW 512		; 每扇区字节数
		BPB_SecPerClus			DB 8		; 每簇多少扇区
		BPB_RsvdSecCnt			DW 36		; Boot 记录占用多少扇区
		BPB_NumFATs				DB 2		; 共有多少 FAT 表
		BPB_RootEntCnt			DW 0		; 根目录文件数最大值
		BPB_TotSec16			DW 0		; 逻辑扇区总数
		BPB_Media				DB 0xF8		; 媒体描述符
		BPB_FATSz16				DW 0		; 每FAT扇区数
		BPB_SecPerTrk			DW 63		; 每磁道扇区数
		BPB_NumHeads			DW 255		; 磁头数(面数)
		BPB_HiddSec				DD 63		; 隐藏扇区数
		BPB_TotSec32			DD 0x7760E8;		; wTotalSectorCount为0时这个值记录扇区数
		BPB_SecPerFat			DD 7626
								DW 0
								DW 0
		BPB_RootClusNum			DD 2
		BPB_FSINFOSec			DW 1
		BPB_BakOfDbrClus		DW 6
						times 12 db  0
		BS_DrvNum				DB 0x80		; 中断 13 的驱动器号
		BS_Reserved1			DB 0		; 未使用
		BS_BootSig				DB 29h		; 扩展引导标记 (29h)
		BS_VolID				DD 7B5Dh		; 卷序列号
		BS_VolLab				DB 'OSMinix.XUE'; 卷标, 必须 11 个字节
		BS_FileSysType			DB 'FAT32   '	; 文件系统类型, 必须 8个字节  
;offset 90Bytes
LABEL_START:
		mov	ax, cs
		mov	ds, ax
		mov	es, ax
		mov sp, BaseOfStack
		
		; 清屏
		mov	ax, 0600h		; AH = 6,  AL = 0h
		mov	bx, 0700h		; 黑底白字(BL = 07h)
		mov	cx, 0			; 左上角: (0, 0)
		mov	dx, 0184fh		; 右下角: (80, 50)
		int	10h			; int 10h
		
		;测试驱动器有效性
		push es
		mov ax, BaseOfLoader
		mov es, ax
		xor cx, cx
.1:	
		inc cl
		push cx	
		mov dl,cl ;Device 
		mov al,01h ;Sectors to read 
		mov ah,02h ;NO.2 Function of int 13h 
		mov ch,00h ;Cylinder 
		mov dh,00h ;Head 
		mov cl,01h ;Sector num 
		mov bx, OffsetOfLoader
		int 13h	
		pop cx
		jc .1	
.2:	
	;cmp cl, 80h
	;jl .1
		pop es
		mov byte[BS_DrvNum],cl
		
	;;; test  int 13h 扩展功能是否可用
TESTDBR:	
		mov	ah, 41h
		mov	bx, 55aah
		mov	dl, cl
		int 	13h
		jnc	EXT_ENABLE
;EXT_UNENABLE
		mov  ax, LoaderNoFound
		call DispStr
		jmp  $
		;;int 13 扩展功能是可用
		
EXT_ENABLE:
;;计算根目录扇区位置
		xor eax, eax
		mov al, [BPB_NumFATs]
		mov ebx, [BPB_SecPerFat]
		mul ebx
		xor ebx, ebx
		mov bx, word[BPB_RsvdSecCnt]
		add eax, ebx
		mov dword[SectorNoOfRootDirectory], eax
		add eax, SectorsOfMBR ;;sectors of MBR
		;;读取根目录两个扇区
		mov dword[disk_addr_pkt + block_num], eax
		mov byte[disk_addr_pkt + packet_size], 10h
		mov byte[disk_addr_pkt + reserved], 0
		mov word[disk_addr_pkt + buffer_addr], OffsetOfLoader
		mov word[disk_addr_pkt + buffer_addr+2], BaseOfLoader
		mov word[disk_addr_pkt + block_count], 2
		mov dword[disk_addr_pkt + block_num + 4], 0
		;mov dword[disk_addr_pkt + block_num], 15351
		;mov dword[disk_addr_pkt + block_num], 63
		mov ah, 42h
		mov dl, [BS_DrvNum]
		mov si, disk_addr_pkt
		int 13h
	
		push es
		mov ax, BaseOfLoader
		mov es, ax
		mov di, OffsetOfLoader
		mov	si, LoaderFileName	; ds:si -> "LOADER  BIN"
		cld
		
		mov dx, 20h		;;两个扇区有32个目录项
LABEL_SEARCH_FOR_LOADERBIN:
		cmp	dx, 0				   ; `. 循环次数控制,
		jz	LABEL_NO_LOADERBIN ;  / 如果已经读完了一个 Sector,
		dec	dx				   ; /  就跳到下一个 Sector
		mov	cx, 11
	LABEL_CMP_FILENAME:
		cmp	cx, 0
		jz	LABEL_FILENAME_FOUND	; 如果比较了 11 个字符都相等, 表示找到
		dec	cx
		lodsb				; ds:si -> al
		cmp	al, byte [es:di]
		jz	LABEL_GO_ON
		jmp	LABEL_DIFFERENT		; 只要发现不一样的字符就表明本 DirectoryEntry
					; 不是我们要找的 LOADER.BIN
	LABEL_GO_ON:
			inc	di
			jmp	LABEL_CMP_FILENAME	; 继续循环

	LABEL_DIFFERENT:
		and	di, 0FFE0h		; else `. di &= E0 为了让它指向本条目开头
		add	di, 20h			;       |
		mov	si, LoaderFileName	;       | di += 20h  下一个目录条目
		jmp	LABEL_SEARCH_FOR_LOADERBIN;    /

LABEL_NO_LOADERBIN:	
		pop es
		mov ax,	LoaderNoFound
		Call	DispStr			; 调用显示字符串例程
		jmp	$			; 无限循环
LABEL_FILENAME_FOUND:
;;寻找LOADER 并加载LOADER
		;;计算文件所在扇区
		and	di, 0FFE0h		; else `. di &= E0 为了让它指向本条目开头
		mov ax, [es:di + 1ah]
		mov word[ClusterNum], ax
		mov ax, [es:di + 14h]
		mov word[ClusterNum + 2], ax
		
		xor eax, eax
		mov al, [BPB_SecPerClus]
		mov ebx, [ClusterNum]
		sub ebx, 2
		mul ebx
		mov ebx, [SectorNoOfRootDirectory]
		add eax, ebx ;;eax 记录文件扇区位置
		add eax, SectorsOfMBR
		
		;;读取8个扇区
		mov dword[disk_addr_pkt + block_num], eax
		mov byte[disk_addr_pkt + packet_size], 10h
		mov byte[disk_addr_pkt + reserved], 0
		mov word[disk_addr_pkt + buffer_addr], OffsetOfLoader
		mov word[disk_addr_pkt + buffer_addr+2], BaseOfLoader
		mov word[disk_addr_pkt + block_count], 8
		mov dword[disk_addr_pkt + block_num + 4], 0
		;mov dword[disk_addr_pkt + block_num], 15351
		;mov dword[disk_addr_pkt + block_num], 63
		mov ah, 42h
		mov dl, [BS_DrvNum]
		mov si, disk_addr_pkt
		int 13h
		
		xor dh, dh
		push dx
		jmp BaseOfLoader:OffsetOfLoader
		;pop es
		;mov ax,	LoaderFound
		;Call	DispStr			; 调用显示字符串例程		
		;jmp	$			; 无限循环
DispStr:
	push bp
	mov bp, ax; ES:BP = 串地址
	mov	cx, 16			; CX = 串长度
	mov	ax, 01301h		; AH = 13,  AL = 01h
	mov	bx, 000ch		; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
	mov	dl, 0
	int	10h	; int 10h
	pop bp
	ret
	;字符串
LoaderFileName		db	"LOADER  BIN", 0 ; LOADER.BIN 之文件名
LoaderFound			db  "Loader  Found   "
LoaderNoFound		db	"Loader No Found!"
;=================变量 =============
struc disk_addr_pkt
	packet_size:  		resb  1  ; 磁盘参数包的尺寸，必须为10H
	reserved:    		resb  1  ;   保留，必须为零
	block_count:  		resw  1  ;   传输的扇区数
	buffer_addr: 		resd  1  ;   内存缓冲区地址（段：偏移）
	block_num:    		resq  1    ;   起始绝对扇区号（即起始扇区的LBA号码）
endstruc
ClusterNum					DD      0
SectorNoOfRootDirectory 	DD 		0
;==============================
times 	510-($-$$)	db	0	; 填充剩下的空间，使生成的二进制代码恰好为512字节
dw 	0xaa55				; 结束标志